package br.edu.ufcg.unknown.exception;

import br.edu.ufcg.unknown.lexico.Token;
import br.edu.ufcg.unknown.semantico.Atributo;
import br.edu.ufcg.unknown.semantico.Tipo;

public class AnalisadorSemanticoUnknownRuntimeException extends UnknownRuntimeException {

	/**
	 * 
	 */
	private static final long serialVersionUID = -1108272379674263692L;

	private static final String LINE_SEPARATOR = System.getProperty("line.separator");

	private Tipo tipoEsperado;

	private Tipo tipoRecebido;

	public AnalisadorSemanticoUnknownRuntimeException(String mensagem) {
		super(mensagem, null);
	}

	public AnalisadorSemanticoUnknownRuntimeException(Token tk) {
		this(tk, false);
	}

	public AnalisadorSemanticoUnknownRuntimeException(Token tk, boolean declarada) {
		super(declarada ? "Linha: " + tk.getLinha() + " Coluna: " + tk.getColuna()
				+ " - Variável já declarada: <<" + tk.getLexema() + ">>" : "Linha: "
				+ tk.getLinha() + " Coluna: " + tk.getColuna()
				+ " - Uso de variável não declarada: <<" + tk.getLexema() + ">>", null);
	}

	public AnalisadorSemanticoUnknownRuntimeException(Atributo atributoEsperado, Tipo tipoRecebido,
			int linha, int coluna) {
		super(
				"Tipos incompatíveis! Linha: "
						+ linha
						+ " Coluna: "
						+ coluna
						+ " - Lado Esq. (ou Esperado): <<"
						+ atributoEsperado.getNome()
						+ ">> <<"
						+ atributoEsperado.getTipo().getTipo()
						+ ">> - Lado Dir. (ou Obtido): "
						+ (tipoRecebido.getToken() != null
								&& !tipoRecebido.getToken().ehPalavraReservada() ? "<<"
								+ tipoRecebido.getToken().getLexema() + ">> " : "") + "<<"
						+ tipoRecebido.getTipo() + ">>", null);
		this.tipoEsperado = atributoEsperado.getTipo();
		this.tipoRecebido = tipoRecebido;
	}

	public AnalisadorSemanticoUnknownRuntimeException(Tipo tipoEsperado, Tipo tipoRecebido) {
		this(tipoEsperado, tipoRecebido, 0, 0);
	}

	public AnalisadorSemanticoUnknownRuntimeException(Tipo tipoEsperado, Tipo tipoRecebido,
			int linha, int coluna) {
		super(
				"Tipos incompatíveis! Linha: "
						+ linha
						+ " Coluna: "
						+ coluna
						+ " -Lado Esq. (ou Esperado): "
						+ (tipoEsperado.getToken() != null
								&& !tipoEsperado.getToken().ehPalavraReservada() ? "<<"
								+ tipoEsperado.getToken().getLexema() + ">> " : "")
						+ "<<"
						+ tipoEsperado.getTipo()
						+ ">> - Lado Dir. (ou Obtido): "
						+ (tipoRecebido.getToken() != null
								&& !tipoRecebido.getToken().ehPalavraReservada() ? "<<"
								+ tipoRecebido.getToken().getLexema() + ">> " : "") + "<<"
						+ tipoRecebido.getTipo() + ">>", null);
		this.tipoEsperado = tipoEsperado;
		this.tipoRecebido = tipoRecebido;
	}

	public boolean equals(Object obj) {

		AnalisadorSemanticoUnknownRuntimeException a = (AnalisadorSemanticoUnknownRuntimeException) obj;

		if (this.tipoEsperado != null && a.tipoEsperado != null) {
			if (!this.tipoEsperado.equals(a.tipoEsperado)) {
				return false;
			}
			if (this.tipoEsperado.getToken() != null && a.tipoEsperado.getToken() != null) {
				// if (!this.tipoEsperado.getToken().equals(a.tipoEsperado.getToken())) {
				// return false;
				// }
			} else if (this.tipoEsperado.getToken() != null || a.tipoEsperado.getToken() != null) {
				return false;
			}
		} else if (this.tipoEsperado != null || a.tipoEsperado != null) {
			return false;
		}

		if (this.tipoRecebido != null && a.tipoRecebido != null) {
			if (!this.tipoRecebido.equals(a.tipoRecebido)) {
				return false;
			}
			if (this.tipoRecebido.getToken() != null && a.tipoRecebido.getToken() != null) {
				// if (!this.tipoRecebido.getToken().equals(a.tipoRecebido.getToken())) {
				// return false;
				// }
			} else if (this.tipoRecebido.getToken() != null || a.tipoRecebido.getToken() != null) {
				return false;
			}
		} else if (this.tipoRecebido != null || a.tipoRecebido != null) {
			return false;
		}

		// TODO Descomentar este código quando os testes estiverem considerando minuncionsamente a
		// linha e coluna do erro
		// if(this.getMessage() != null && a.getMessage() != null){
		// if(!this.getMessage().equals(a.getMessage())){
		// return false;
		// }
		// } else if(this.getMessage() != null || a.getMessage() != null){
		// return false;
		// }

		return true;
	}

	public String toString() {
		StringBuilder sb = new StringBuilder();

		sb.append("Mensagem de Erro:");
		sb.append(LINE_SEPARATOR);
		sb.append(super.toString());
		sb.append(LINE_SEPARATOR);
		sb.append("Tipo esperado: ");
		sb.append(this.tipoEsperado);
		sb.append(LINE_SEPARATOR);
		sb.append("Tipo recebido: ");
		sb.append(this.tipoRecebido);

		return sb.toString();

	}
}
